package com.ec.rs.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ec.api.client.ElderProfileClient;
import com.ec.common.constant.CacheConstants;
import com.ec.common.domain.PageVO;
import com.ec.common.domain.Result;
import com.ec.common.utils.CacheClient;
import com.ec.rs.domain.vo.BedStatsVO;
import com.ec.rs.domain.dto.CreateBedDTO;
import com.ec.rs.domain.dto.UpdateBedDTO;
import com.ec.rs.domain.po.Bed;
import com.ec.rs.enums.BedStatus;
import com.ec.rs.enums.RequestType;
import com.ec.rs.mapper.BedMapper;
import com.ec.rs.service.BedService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@RequiredArgsConstructor
public class BedServiceImpl implements BedService {
    private final BedMapper bedMapper;
    private final CacheClient cacheClient;
    private final ElderProfileClient elderProfileClient;

    @Override
    public Result<PageVO<Bed>> listBeds(int page, int size, String status, String roomNumber) {
        Page<Bed> pageObj = new Page<>(page, size);
        QueryWrapper<Bed> wrapper = new QueryWrapper<>();
        if (status != null) {
            BedStatus bedStatus = BedStatus.of(status);
            wrapper.eq("status", bedStatus.getValue());
        }
        if (roomNumber != null && !roomNumber.isEmpty()) {
            wrapper.like("room_number", roomNumber);
        }
        Page<Bed> resultPage = bedMapper.selectPage(pageObj, wrapper);
        return Result.ok(PageVO.of(resultPage));
    }

    @Override
    public Result<Bed> getBedById(Integer id) {
        Bed bed = cacheClient.queryWithPassThrough(
                CacheConstants.CACHE_BED_KEY,
                id,
                Bed.class,
                bedMapper::selectById,
                CacheConstants.DEFAULT_TTL,
                TimeUnit.MINUTES
        );
        if (bed == null) {
            return Result.error("床位不存在");
        }
        return Result.ok(bed);
    }

    @Override
    @Transactional
    public Result<Void> createBed(CreateBedDTO dto) {
        QueryWrapper<Bed> wrapper = new QueryWrapper<>();
        wrapper.eq("room_number", dto.getRoomNumber())
                .eq("bed_number", dto.getBedNumber());
        if (bedMapper.selectCount(wrapper) > 0) {
            return Result.error("床位已存在");
        }
        Bed bed = Bed.builder()
                .bedNumber(dto.getBedNumber())
                .roomNumber(dto.getRoomNumber())
                .status(BedStatus.VACANT)
                .costPerMonth(dto.getCostPerMonth())
                .notes(dto.getNotes())
                .build();
        bedMapper.insert(bed);
        return Result.ok();
    }

    @Override
    @Transactional
    public Result<Void> updateBed(Integer id, UpdateBedDTO dto) {
        Bed bed = bedMapper.selectById(id);
        if (bed == null) {
            return Result.error("Bed not found");
        }
        if (dto.getStatus() != null) {
            if (dto.getStatus() == BedStatus.OCCUPIED && dto.getOccupiedByUserId() == null) {
                return Result.error("暂用床位必须指定老人用户ID");
            }
            if (dto.getStatus() == BedStatus.VACANT && bed.getOccupiedByUserId() != null) {
                // 释放床位，同步更新老人档案
                // 调用 profile-service 更新床位ID为 null
                Result<Boolean> bedResult = elderProfileClient.updateBedId(bed.getOccupiedByUserId(), (long) -1);
                if (!bedResult.getData()) {
                    throw new RuntimeException("更新老人床位ID失败: " + bedResult.getMsg());
                }
                // 调用 profile-service 更新入住状态
                Result<Void> statusResult = elderProfileClient.updateElderlyStatusByUserId(bed.getOccupiedByUserId(), "退住");
                if (!statusResult.success()) {
                    throw new RuntimeException("更新老人入住状态失败: " + statusResult.getMsg());
                }
            }
            bed.setStatus(dto.getStatus());
            bed.setOccupiedByUserId(dto.getOccupiedByUserId());
        }
        if (dto.getCostPerMonth() != null) {
            bed.setCostPerMonth(dto.getCostPerMonth());
        }
        if (dto.getNotes() != null) {
            bed.setNotes(dto.getNotes());
        }
        bedMapper.updateById(bed);
        if (bed.getStatus() == BedStatus.OCCUPIED && bed.getOccupiedByUserId() != null) {
            // 更新老人档案
            // 调用 profile-service 更新床位ID
            Result<Boolean> bedResult = elderProfileClient.updateBedId(bed.getOccupiedByUserId(), Long.valueOf(bed.getId()));
            if (!bedResult.getData()) {
                throw new RuntimeException("更新老人床位ID失败: " + bedResult.getMsg());
            }

            // 调用 profile-service 更新入住状态
            Result<Void> statusResult = elderProfileClient.updateElderlyStatusByUserId(bed.getOccupiedByUserId(), "在住");
            if (!statusResult.success()) {
                throw new RuntimeException("更新老人入住状态失败: " + statusResult.getMsg());
            }

        }
        return Result.ok();
    }

    @Override
    @Transactional
    public Result<Void> deleteBed(Integer id) {
        Bed bed = bedMapper.selectById(id);
        if (bed == null) {
            return Result.error("床位找不到");
        }
        if (bed.getStatus() == BedStatus.OCCUPIED) {
            return Result.error("床位已被占用，不能删除");
        }
        bedMapper.deleteById(id);
        return Result.ok();
    }

    @Override
    public Result<BedStatsVO> getBedStats() {
        BedStatsVO stats = new BedStatsVO();
        long totalBeds = bedMapper.selectCount(new QueryWrapper<>());
        long vacantBeds = bedMapper.selectCount(new QueryWrapper<Bed>().eq("status", BedStatus.VACANT.getValue()));
        long occupiedBeds = bedMapper.selectCount(new QueryWrapper<Bed>().eq("status", BedStatus.OCCUPIED.getValue()));
        stats.setTotalBeds(totalBeds);
        stats.setVacantBeds(vacantBeds);
        stats.setOccupiedBeds(occupiedBeds);
        stats.setOccupancyRate(totalBeds > 0 ? (double) occupiedBeds / totalBeds * 100 : 0.0);
        return Result.ok(stats);
    }
}

